<script setup>
  import * as math from 'mathjs';
  import { onMounted, reactive, ref, computed, watch, nextTick } from 'vue';

  defineOptions({name: ''});
  const props = defineProps({
    // width: {type: Number, default: 120}, // 水印的宽度，
    // height: {type: Number, default: 64}, // 水印的高度，
    rotate: {type: Number, default: -30}, // 水印的旋转角度, 单位 °，取值范围[-90, 90]
    zIndex: {type: Number, default: -1}, // 水印元素的z-index值
    image: {type: String, default: ''}, // 水印图片，建议使用 2x 或 3x 图像
    content: {type: String, default: '测试水印[123456789]'}, // 水印文本内容
    font: {
      type: Object, default: () => {
        return {
          // color: 'rgba(225, 225, 225, 0.5)', // 字体颜色
          color: 'rgba(0, 0, 0, 0.5)', // 字体颜色
          fontSize: 20, // 字体大小
          fontWeight: 'bold', // 字重 normal
          fontFamily: 'Georgia', // 字体 sans-serif
          fontStyle: 'normal', // 字体样式 normal
          textAlign: 'left', // 文本对齐
          textBaseline: 'top', // 文本基线 hanging\alphabetic\middle\bottom\top}
        }
      },
    },
    gap: {type: Array, default: () => [50, 100]}, // 水印之间的间距[行，纵]
    offset: {type: Array, default: () => [0, 0]}, // 水印从容器左上角的偏移 默认值为 gap/2 [top, left]
  })
  const canvasWidth = ref(120);
  const canvasHeight = ref(60);
  const imgSrc = ref('');
  const emits = defineEmits(['on-ok']);
  const watermarkCanvas = ref(null);
  const myCanvas = ref(null);
  // watch(() => foo, (newValue, oldValue) => {})
  watch(() => [props.rotate, props.zIndex, props.image, props.content], () => {
    nextTick(() => {
      initCanvas();
    })
  });
  watch(() => [props.font, props.gap, props.offset], () => {
    nextTick(() => {
      initCanvas();
    })
  }, {deep: true})
  onMounted(() => {
    nextTick(() => {
      initCanvas();
    })
  });
  
  const initCanvas = () => {
    // width, height, 
    const {rotate, font, content, gap, image} = props;
    console.log('content', content);
    const {color, fontWeight, fontFamily, fontStyle, textAlign, textBaseline} = font;
    const fontSize = font.fontSize + 'px';
    let _imgSrc = '', contentLen = 0, contentHeight = 0, radian = 0;
    // 计算旋转弧度，弧度 = (Math.PI/180) * 角度
    if(rotate) {
      radian = Math.abs(rotate) > 90 ? 0 : Math.abs(rotate) / 360 * 2 * Math.PI
    }
    // 先将文字转为图片
    if(content) {
      // 获取水印文本长度以及高度
      const contentSpan = document.getElementById('watermarkContent');
      contentLen = contentSpan.offsetWidth;
      contentHeight = contentSpan.offsetHeight;

      if(!watermarkCanvas.value) {
        // 创建水印 Canvas 对象实例
        watermarkCanvas.value = document.createElement('canvas');
        // 放到watermarkBox中
        document.getElementById('watermarkBox')?.appendChild(watermarkCanvas.value);
        watermarkCanvas.value.setAttribute('style', 'position: fixed;left: -10000px;top: -10000px');
      }
      // 初始化水印画布大小
      watermarkCanvas.value.width = contentLen;
      watermarkCanvas.value.height = contentHeight;
      // 水印 Canvas 对象上下文实例（动画动作绘图等都是在他的身上完成）
      const watermarkContext = watermarkCanvas.value.getContext("2d");
      // 设置填充文字样式
      watermarkContext.fillStyle = color;
      watermarkContext.textAlign = textAlign;
      watermarkContext.textBaseline = textBaseline;
      // normal bold 24px PingFang SC, PingFang SC-Medium
      const fontList = [fontStyle, fontWeight, fontSize, fontFamily].filter(item => item)
      watermarkContext.font = fontList.join(' ');
      // 居中显示水印
      watermarkContext.fillText(content, 0, 0);
      // 绘制
      watermarkContext.stroke();
      // 导出透明背景的图片
      const dataURL = watermarkCanvas.value.toDataURL('image/png', 1);
      _imgSrc = dataURL
    }
    // 而后将图片作为基本单元重新放入canvas进一步进行旋转间隔等
    if(_imgSrc || image) {
      if(!myCanvas.value) {
        // 创建新 Canvas 对象实例，处理间隔以及旋转，图片水印
        myCanvas.value = document.createElement('canvas');
        // 放到watermarkBox中
        document.getElementById('watermarkBox')?.appendChild(myCanvas.value);
        myCanvas.value.setAttribute('style', 'position: fixed;left: -10000px;top: -10000px');
      }
      // 新 Canvas 对象上下文实例（动画动作绘图等都是在他的身上完成）
      const myContext = myCanvas.value.getContext("2d");
      const watermarkImg = new Image()
      watermarkImg.src = _imgSrc || image;
      watermarkImg.onload = () => {
        if(rotate) { // 有角度，则需计算出水印倾斜后的实际宽高
          let mergeWeight = watermarkImg.height * math.sin(radian) + watermarkImg.width * math.cos(radian);
          let mergeHeight = watermarkImg.width * math.sin(radian) + watermarkImg.height * math.cos(radian);
          if(Math.abs(rotate) === 90) { // 90°特殊处理
            mergeWeight = watermarkImg.height * 1 + watermarkImg.width * 0;
            mergeHeight = watermarkImg.width * 1 + watermarkImg.height * 0;
          }
          canvasWidth.value = myCanvas.value.width = mergeWeight + gap[0];
          canvasHeight.value = myCanvas.value.height = mergeHeight + gap[1];
          // 旋转是以画布的左上角为原点旋转的，先将原点平移到画布中心位置
          myContext.translate(mergeWeight / 2, mergeHeight / 2);
          myContext.rotate(rotate > 0 ? radian : -radian);
          // 水印是按照画布的中心点旋转的，画布的真实长宽也是按照水印的宽高以及旋转角度计算出来的
          // 所以此时水印的X轴绝对处于未添加间隔前画布的对角线上且原点处于画布的对角线的交点上
          // 故此只需要计算出来水印应该往X轴的反方向移动多少像素，以及向Y轴移动水印高的一半即可
          let dx = 0;
          if(Math.abs(rotate) > 45) {
            dx = -((mergeHeight / math.sin(radian)) / 2);
          } else {
            dx = -((mergeWeight / 2) / math.cos(radian));
          }
          if(Math.abs(rotate) === 90) { // 90°转换为弧度后计算出来的值会存在问题
            dx = -(mergeHeight / 2);
          }
          myContext.translate(dx + 10, -watermarkImg.height / 2);
          // 间隙
          if(gap[0]) {
            let dy = math.sin(radian) * (gap[0] / 2);
            let dx = dy / math.tan(radian);
            myContext.translate(dx, rotate < 0 ? dy : -dy);
          }
          if(gap[1]) {
            let dy = math.cos(radian) * (gap[1] / 2);
            let dx = math.tan(radian) * dy;
            myContext.translate(rotate < 0 ? -dx : dx, dy);
          }
          // 绘制
          myContext.drawImage(watermarkImg, 0, 0);
        } else { // 无角度，则宽高只需要在原始水印加上对应的间隔即可
          canvasWidth.value = gap[0] + watermarkImg.width;
          canvasHeight.value = gap[1] + watermarkImg.height;
          myCanvas.value.width = canvasWidth.value;
          myCanvas.value.height = canvasHeight.value;
          // 绘制(居中显示)
          myContext.drawImage(watermarkImg, gap[0] / 2, gap[1] / 2);
        }
        // 导出透明背景的图片
        const myDataURL = myCanvas.value.toDataURL('image/png', 1);
        imgSrc.value = myDataURL;
      }
    }
  }

  // 子组件暴露
  defineExpose({});

</script>

<template>
  <div id="watermarkBox" class="props" style="position: relative;">
    <slot></slot>
    <div :style="{
      'z-index': zIndex,
      'position': 'absolute',
      'top': props.offset[0] + 'px',
      'left': props.offset[1] + 'px',
      'width': '100%',
      'height': '100%',
      'pointer-events': 'none',
      'background-repeat': 'repeat',
      'background-position': '0px 0px',
      'background-image': `url(${imgSrc})`,
    }" class="watermarkBg"></div>
    <!-- 用于获取水印文字的宽高 -->
    <span id="watermarkContent" :style="{
      position: 'fixed',
      left: '-10000px',
      top: '-10000px',
      fontSize: props.font.fontSize + 'px',
      fontFamily: props.font.fontFamily,
      fontWeight: props.font.fontWeight,
      fontStyle: props.font.fontStyle,
    }">{{ props.content }}</span>
  </div>
</template>

<style lang="less" scoped>

</style>
